package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {


    @Resource
    private VodService vodService;

    @Resource
    private TrackStatMapper trackStatMapper;

    @Resource
    private AlbumInfoMapper albumInfoMapper;

    @Resource
    private UserInfoFeignClient userInfoFeignClient;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveTrackInfo(TrackInfoVo trackInfoVo, Long userId) {
        //向声音表添加数据
        //构造声音数据
        TrackInfo trackInfo = new TrackInfo();
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        //设置用户id
        trackInfo.setUserId(userId);
        //获取专辑的最新序号
        TrackInfo preTrackInfo = this.getOne(new LambdaQueryWrapper<TrackInfo>()
                .eq(TrackInfo::getAlbumId, trackInfoVo.getAlbumId())
                .orderByDesc(TrackInfo::getId)
                .select(TrackInfo::getOrderNum).
                last(" limit 1 "));
        trackInfo.setOrderNum(preTrackInfo.getOrderNum() + 1);
        //根据流媒体id获取声音对象数据
        TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
        trackInfo.setMediaSize(trackMediaInfoVo.getSize());
        trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
        trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfoVo.getDuration()));
        trackInfo.setMediaType(trackMediaInfoVo.getType());
        this.save(trackInfo);

        //初始化声音的一些信息向track_stat
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COLLECT);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PRAISE);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COMMENT);
        //关系专辑里的声音数量
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        albumInfoMapper.updateById(albumInfo);
    }

    @Override
    public IPage<TrackListVo> findUserTrackPage(Page<TrackListVo> page, TrackInfoQuery trackInfoQuery) {
        return this.baseMapper.selectUserTrackPage(page, trackInfoQuery);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeTrackInfo(Integer trackId) {
        //删除声音还要将专辑里的声音数量减一，和声音的统计数据删除
        //删除声音
        //因为修改专辑要用到声音里的数据
        TrackInfo trackInfo = this.getById(trackId);
        this.baseMapper.deleteById(trackId);
        //删除声音的相关统计数据
        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, trackId));
        //将专辑里的声音数量减一
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        albumInfoMapper.updateById(albumInfo);
        //修改序列号
        this.baseMapper.updateTrackNum(trackInfo.getAlbumId(), trackInfo.getOrderNum());
        //删除流媒体数据
        vodService.removeMediaInfo(trackInfo.getMediaFileId());
    }

    @Override
    public TrackInfo getTrackInfo(Integer trackId) {
        return this.getById(trackId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTrackInfo(Integer trackId, TrackInfoVo trackInfoVo) {
        //track_info track_stat
        TrackInfo trackInfo = this.getById(trackId);
        String mediaFileId = trackInfoVo.getMediaFileId();
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        //判断声音是否被修改过了
        if (!mediaFileId.equals(trackInfo.getMediaFileId())) {
            //获取到现在的流媒体数据
            TrackMediaInfoVo mediaInfo = vodService.getMediaInfo(mediaFileId);
            if (mediaInfo == null) {
                throw new GuiguException(ResultCodeEnum.FAIL);
            }
            trackInfo.setMediaSize(mediaInfo.getSize());
            trackInfo.setMediaUrl(mediaInfo.getMediaUrl());
            trackInfo.setMediaDuration(BigDecimal.valueOf(mediaInfo.getDuration()));
            trackInfo.setMediaType(mediaInfo.getType());
            //删除流媒体里原有的声音
            vodService.removeMediaInfo(trackInfo.getMediaFileId());
        }

        this.baseMapper.updateById(trackInfo);
    }

    @Override
    public IPage<AlbumTrackListVo> findAlbumTrackPage(Long albumId, Page<AlbumTrackListVo> albumTrackListVoPage, Long userId) {
        //先获取到专辑的声音列表
        IPage<AlbumTrackListVo> pageInfo = this.baseMapper.selectAlbumTrackPage(albumId, albumTrackListVoPage);
        //先获取到专辑信息，根据专辑的类型判断怎么给声音列表设置收费
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        //判断是否有用户id
        if (userId == null) {
            //判断专辑的收费类型
            if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfo.getPayType())) {
                //用户未登录情况下，在付费情况下只有免费试听集数才可以播放
                List<AlbumTrackListVo> records = pageInfo.getRecords();
                records.stream()
                        .filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > albumInfo.getTracksForFree())
                        .forEach(albumTrackListVo ->
                                albumTrackListVo.setIsShowPaidMark(true));
            }
            return pageInfo;
        }
        //当用户登录时
        //如果是vip免费
        boolean isShowPaidMark = false;
        if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(albumInfo.getPayType())) {
            //获取用户信息判断是否是vip
            Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfoVo(userId);
            Assert.notNull(userInfoVoResult, "返回用户信息为空");
            UserInfoVo userInfoVo = userInfoVoResult.getData();
            Assert.notNull(userInfoVo, "返回用户信息内容为空");
            if (userInfoVo.getIsVip() == 0) {
                isShowPaidMark = true;
            }
            if (userInfoVo.getIsVip() == 1 && userInfoVo.getVipExpireTime().before(new Date())) {
                isShowPaidMark = true;
            }
        } else if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(albumInfo.getPayType())) {
            isShowPaidMark = true;
        }
        //专辑要付费的情况
        if (isShowPaidMark) {
            //获取到用户以及购买的声音，这些声音要排除
            //	处理试听声音，获取需要付费的声音列表
            List<AlbumTrackListVo> albumTrackNeedPaidListVoList = pageInfo.getRecords().stream()
                    .filter(albumTrackListVo -> albumTrackListVo.getOrderNum() >
                            albumInfo.getTracksForFree()).toList();
            if (!CollectionUtils.isEmpty(albumTrackNeedPaidListVoList)) {
                List<Long> trackIds = albumTrackNeedPaidListVoList.stream().map(AlbumTrackListVo::getTrackId).toList();
                Result<Map<Long, Integer>> mapResult = userInfoFeignClient.userIsPaidTrack(albumId, trackIds);
                Assert.notNull(mapResult, "返回购买声音信息为空");
                Map<Long, Integer> map = mapResult.getData();
                Assert.notNull(map, "返回购买声音内容为空");
                for (AlbumTrackListVo albumTrackListVo : albumTrackNeedPaidListVoList) {
                    //给albumTrackListVo赋值是否要付费
                    albumTrackListVo.setIsShowPaidMark(map.get(albumTrackListVo.getTrackId()) == 0);
                }
            }
        }
        return pageInfo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateTrackStat(TrackStatMqVo trackStatMqVo) {
        //更新声音的统计数据
        trackStatMapper.updateTrackStat(trackStatMqVo.getTrackId(), trackStatMqVo.getStatType(), trackStatMqVo.getCount());
        //更新专辑的统计数据,因为这个是个通用方法，只有在更新播放量时才会跟着更新专辑的播放量
        if (SystemConstant.TRACK_STAT_PLAY.equals(trackStatMqVo.getStatType())) {
            albumInfoMapper.updateAlbumStat(trackStatMqVo.getAlbumId(), SystemConstant.ALBUM_STAT_PLAY, trackStatMqVo.getCount());
        }
    }

    @Override
    public List<Map<String, Object>> findUserTrackPaidList(Long trackId, Long userId) {
        //构建返回对象
        List<Map<String, Object>> list = new ArrayList<>();
        //根据声音id获取声音详情
        TrackInfo trackInfo = this.getById(trackId);
        //获取专辑信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
        //远程调用:得到该用户购买了该专辑的多少声音
        Result<List<Long>> trackIdListResult = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
        Assert.notNull(trackIdListResult, "声音Id集合不为空");
        List<Long> trackIdList = trackIdListResult.getData();
        Assert.notNull(trackIdList, "声音专辑Id 不为空");
        //根据专辑id获取专辑里比声音id大的声音列表
        LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId());
        queryWrapper.ge(TrackInfo::getOrderNum, trackInfo.getOrderNum());
        //获取到所有付费声音列表
        List<TrackInfo> trackInfoList = this.baseMapper.selectList(queryWrapper);
        //将已经购买过的声音排除
        List<TrackInfo> trackInfos = trackInfoList.stream()
                .filter(trackInfo1 -> !trackIdList.contains(trackInfo1.getId())).toList();
        //构建分集购买列表
        //本集
        int totalTrackCount = trackInfos.size();
        if (totalTrackCount > 0) {
            this.addToPurchaseList(list, "本集", albumInfo.getPrice(), 0);
        }
        // 分段构造购买数据列表
        for (int i = 10; i <= 50; i += 10) {
            if (totalTrackCount > i) {
                addToPurchaseList(list, "后" + i + "集", albumInfo.getPrice().multiply(new BigDecimal(i)), i);
            } else {
                addToPurchaseList(list, "后" + totalTrackCount + "集", albumInfo.getPrice().multiply(new BigDecimal(totalTrackCount)), totalTrackCount);
                break;
            }
        }
        return list;
    }

    @Override
    public List<TrackInfo> findPaidTrackInfoList(Long trackId, Integer trackCount) {
        //获取的声音信息
        TrackInfo trackInfo = this.getById(trackId);
        //远程调用:得到该用户购买了该专辑的多少声音
        Result<List<Long>> trackIdListResult = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
        Assert.notNull(trackIdListResult, "声音Id集合不为空");
        List<Long> trackIdList = trackIdListResult.getData();
        Assert.notNull(trackIdList, "声音专辑Id 不为空");
        List<TrackInfo> trackInfos = new ArrayList<>();
        if (trackCount > 0) {
            LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId());
            queryWrapper.gt(TrackInfo::getOrderNum, trackInfo.getOrderNum());
            queryWrapper.orderByAsc(TrackInfo::getOrderNum);
            if (!CollectionUtils.isEmpty(trackIdList)) {
                queryWrapper.notIn(TrackInfo::getId, trackIdList);
            }
            queryWrapper.last("limit " + trackCount);
            trackInfos = this.baseMapper.selectList(queryWrapper);
        } else {
            trackInfos.add(trackInfo);
        }
        return trackInfos;
    }


    /**
     * 初始化统计数量
     *
     * @param trackId
     * @param trackType
     */
    private void saveTrackStat(Long trackId, String trackType) {
        TrackStat trackStat = new TrackStat();
        trackStat.setTrackId(trackId);
        trackStat.setStatType(trackType);
        trackStat.setStatNum(0);
        this.trackStatMapper.insert(trackStat);
    }


    /**
     * 辅助方法：向购买数据列表中添加项目
     */
    private void addToPurchaseList(List<Map<String, Object>> list, String name, BigDecimal price, int trackCount) {
        Map<String, Object> map = new HashMap<>();
        map.put("name", name);
        map.put("price", price);
        map.put("trackCount", trackCount);
        list.add(map);
    }
}
